/**
 * 
 */
package moore;

import helpers.AutomataOperations;
import helpers.HandleHashSet;
import helpers.Partitions;
import interfaces.*;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;


import automaton.DFA;

/**
 * @author LE VAN LINH
 *
 */
public class Moore_Algorithm {
	
	public static HashSet<HandleHashSet> moore_Equivalence(DFA automata)
	{
		HashSet<HandleHashSet> p0= Partitions.initial(automata);		
		HashSet<HandleHashSet> q = new HashSet<HandleHashSet>();
		
		HashSet<HandleHashSet> temp;
		do{
			temp = new HashSet<HandleHashSet>();
			q = p0;
			Iterator<HandleHashSet> setOfPartitions = p0.iterator();
			char beginLabel = 'a';
			while(setOfPartitions.hasNext()){
				HandleHashSet hsettemp = setOfPartitions.next();
				if(hsettemp.size() > 1){
					HashSet<HandleHashSet> p1 = setEquiv(automata,p0,hsettemp);
					for (HandleHashSet hHashSet : p1) {
						hHashSet.setLabel(beginLabel);
						beginLabel++;
						temp.add(hHashSet);
					}
				}else{
					hsettemp.setLabel(beginLabel);
					beginLabel++;
					temp.add(hsettemp);
				}
				
			}
			p0 = temp;
		}while(!p0.equals(q));
		
		return p0;
	}

	private static HashSet<HandleHashSet> setEquiv(DFA automata,
			HashSet<HandleHashSet> p0, HandleHashSet hsettemp) {
		Map<State,Character> mapS = new HashMap<State, Character>();
		
		for (HandleHashSet hset : p0) {
			for (State state : hset) {
				if(state != null
						&& state.label().toString().compareTo("")!=0)
					mapS.put(state,hset.getLabel());
			}
		}
		
		Map<State,String> mapS2 = new HashMap<State, String>();
		Iterator<String> listLabel;
		for (State state : hsettemp) {
			String labelSet = "";
			listLabel = AutomataOperations.getLabels(automata).iterator();
			while(listLabel.hasNext()){
				String label = listLabel.next();
				if(label.compareTo("") != 0){
					Transition<String> tran = automata.getDFA().get(state).get(label);
					if(tran !=null && tran.target() != null){
						State target = automata.getDFA().get(state).get(label).target();
						if(mapS.get(target)!=null){
							labelSet+=mapS.get(target).toString();													
						}else{
							labelSet+="_";
						}						
					}else{
						labelSet+="_";
					}
					mapS2.put(state, labelSet);
				}
			}
		}
		HashSet<HandleHashSet> result = new HashSet<HandleHashSet>();
		
		for(Map.Entry<State,String> entry: mapS2.entrySet()){			
			HandleHashSet set = new HandleHashSet();
			set.add(entry.getKey());
			for(Map.Entry<State,String> entry2: mapS2.entrySet()){
				if(entry2.getValue().compareTo(entry.getValue())==0
						&& !entry2.getKey().equals(entry.getKey())){
					set.add(entry2.getKey());
					mapS2.remove(entry2);
				}
			}
			result.add(set);
			mapS2.remove(entry);
		}
				
		return result;
	}
}
